package com.bonc.ioc.demo.aop;

import com.alibaba.fastjson.JSON;
import com.bonc.ioc.common.util.AppReply;
import com.bonc.ioc.demo.constant.UserInfo;
import com.github.houbb.heaven.util.lang.ObjectUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.tomcat.util.codec.binary.Base64;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

/**
 * @version V0.1
 * @project_name：zhlq-my
 * @package_name：com.bonc.ioc.common.aop
 * @describe：***
 * @creater lyh
 * @creat_time 2018/11/2 16:44
 * @changer ***
 * @change_time 2018/11/2 16:44
 * @remark ***
 */
@Aspect
@Component
@Slf4j
public class AppAuthAnnotationAspect {

    @Value("${mcp.common.login.session.timeout:7200}")
    private Long sessionTimeout;

    @Value("${mcp.common.login.enableToken:true}")
    private boolean enableToken;

    @Autowired
    StringRedisTemplate redisTemplate;
    @Autowired
    private HttpServletRequest request;

    public AppAuthAnnotationAspect() {
//        log.info("初始化接口参数非空判断切面类...");
    }

    @Pointcut("@annotation(com.bonc.ioc.demo.aop.AppAuthAnnotation)")
    public void controllerInteceptor() {
    }

    @Around("controllerInteceptor()")
    public Object before(ProceedingJoinPoint pjp) throws Throwable {
        if(enableToken) {
            //获取被注解的方法
            MethodInvocationProceedingJoinPoint mjp = (MethodInvocationProceedingJoinPoint) pjp;
            MethodSignature signature = (MethodSignature) mjp.getSignature();
            Method method = signature.getMethod();
            String tokenId = null;
            AppAuthAnnotation systemLogAnnotation = method.getAnnotation(AppAuthAnnotation.class);
            if (systemLogAnnotation != null) {
                tokenId = request.getHeader("tokenId");
                if (StringUtils.isEmpty(tokenId)) {
                    return AppReply.login();
                }
            }
            if (null == redisTemplate) {
                BeanFactory factory = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getServletContext());
                redisTemplate = (StringRedisTemplate) factory.getBean("stringRedisTemplate");
            }
            //从redis中获取userId
            String user = redisTemplate.opsForValue().get(tokenId);
            log.info("user = {}", user);

            if (StringUtils.isEmpty(user)) {
                return AppReply.relogin();
            }

            UserInfo userInfo = null;

            try {
                userInfo = JSON.parseObject(new String(Base64.decodeBase64(user)), UserInfo.class);
            } catch (Exception ex) {
                return AppReply.relogin();
            }

            String s = userInfo.getId();
            if (ObjectUtil.isNull(s)) {
                return AppReply.relogin();
            }

            //判断是否在别处登录
            String sessionId = redisTemplate.opsForValue().get(s);
            if (sessionId == null || !sessionId.contains(tokenId)) {
                return AppReply.relogin1();
            }

            //判断注解中的userId是否为true，不为true时判断userId和tokenId是否是同一用户
            if (systemLogAnnotation.userId()) {
                //获取参数中userId的值
                String userId = request.getParameter("userId");
                if (StringUtils.isEmpty(userId)) {
                    return AppReply.error("userId不能为空");
                }
                //如果根据tokenId获取的userId与接口中传入的userId不同，那么证明不是同一用户
                if (!(s.toString()).equals(userId)) {
                    return AppReply.error("userId传入错误");
                }

            }
            //保持登录
            redisTemplate.expire(tokenId, sessionTimeout, TimeUnit.SECONDS);
            redisTemplate.expire(s, sessionTimeout, TimeUnit.SECONDS);
        }

        //如果没有报错,放行
        return pjp.proceed();
    }
}